#ifndef DETECT_NODES_H
#define DETECT_NODES_H

#include <string>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <boost/shared_ptr.hpp>

#include "cmdline.h"
#include "sequence_corpus_reader.h"

class FeatureMap
{
	friend std::ostream& operator<<(std::ostream&, const FeatureMap&);
	friend std::istream& operator>>(std::istream&, FeatureMap&);
public:
	FeatureMap();
	~FeatureMap();

	int add(const std::string &f);
	int index(const std::string &f);
	std::string string(int i);
	int num_features() const { return myNumFeatures; }
	void freeze() { myFrozen = true; }
	bool frozen() { return myFrozen; }

	void read_tag_map(std::istream &in);
	int map_tag(const std::string& word, int tag);
	size_t word_tags(const std::string& word);

private:
	int myNumFeatures;
	bool myFrozen;
	std::map<std::string,int> myIndex; 
	std::map<int,std::string> myReverseIndex; 
	std::map<std::string,std::vector<int> > myTagMap; 
		
};
typedef boost::shared_ptr<FeatureMap> FeatureMapPtr;

class NodeDetector
{
public:
	typedef std::map<int,float> FeatureSet;
	typedef boost::shared_ptr<FeatureSet> FeatureSetPtr;
	struct NodeFeatures
	{
		bool gold;
		std::string word;
		FeatureSet features;
	};
		typedef boost::shared_ptr<NodeFeatures> NodeFeaturesPtr;
	struct RowFeatures
	{
		std::string tag;
		std::string word;
		std::vector<NodeFeaturesPtr> nodes;
		FeatureSet null;
		size_t gold;
	};
	typedef boost::shared_ptr<RowFeatures> RowFeaturesPtr;
	struct Chart
	{
		Chart(size_t len) : features(len) {}
		size_t order;
		int start_label;
		int end_label;
		size_t labels;
		SequenceCorpusReader::SegmentLabellingPtr gold;
		std::vector<std::vector<RowFeaturesPtr> > features;
	};
	typedef boost::shared_ptr<Chart> ChartPtr;

public:
	NodeDetector(boost::shared_ptr<Parameters> p, bool detect_null=false);
	~NodeDetector();

	ChartPtr next();
	void skip();
	void reset();

	FeatureMapPtr feature_map() { return myFeatureMap; }
	FeatureSet merge_features(const FeatureSet &lhs, const FeatureSet &rhs);
	void add_features(FeatureSet &lhs, const FeatureSet &rhs);

private:
	void detect();
	void read_label_features(char *);

private:
	boost::shared_ptr<Parameters> myParameters;
	SequenceCorpusReaderPtr myCorpusReader;
	FeatureMapPtr myFeatureMap;
	std::map<int,std::set<std::string> > myLabelFeatures;
};
typedef boost::shared_ptr<NodeDetector> NodeDetectorPtr;

#endif
